package com.easycms.web.monitor.jobutils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.easycms.web.monitor.domain.MonitorJob;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * @author yushuo
 * @className
 * @descripton TODO
 * @date 2021/6/3 16:37
 **/
public class JobInvokeUtil {
        /**
         * 执行方法
         * @param job 系统任务
         */
        public static void invokeMethod(MonitorJob job) throws Exception {
            String invokeTarget = job.getInvokeTarget();
            String beanName = getBeanName(invokeTarget);
            String methodName = getMethodName(invokeTarget);
            List<Object[]> methodParams = getMethodParams(invokeTarget);

            if (!isValidClassName(beanName)) {
                Object bean = ReflectUtil.newInstance(beanName);
                invokeMethod(bean, methodName, methodParams);
            } else {
                Object bean = Class.forName(beanName).newInstance();
                invokeMethod(bean, methodName, methodParams);
            }
        }

        /**
         * 调用任务方法
         * @param bean 目标对象
         * @param methodName 方法名称
         * @param methodParams 方法参数
         */
        private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
                throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
                InvocationTargetException {
            if (CollUtil.isNotEmpty(methodParams)) {
                Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
                method.invoke(bean, getMethodParamsValue(methodParams));
            } else {
                Method method = bean.getClass().getDeclaredMethod(methodName);
                method.invoke(bean);
            }
        }

        /**
         * 校验是否为为class包名
         * @param invokeTarget 名称
         * @return true是 false否
         */
        public static boolean isValidClassName(String invokeTarget) {
            return StrUtil.count(invokeTarget, ".") > 1;
        }

        /**
         * 获取bean名称
         * @param invokeTarget 目标字符串
         * @return bean名称
         */
        public static String getBeanName(String invokeTarget) {
            String beanName = StrUtil.subBefore(invokeTarget, "(",false);
            return StrUtil.subBefore(beanName, ".",true);
        }

        /**
         * 获取bean方法
         * @param invokeTarget 目标字符串
         * @return method方法
         */
        public static String getMethodName(String invokeTarget) {
            String methodName = StrUtil.subBefore(invokeTarget, "(",false);
            return StrUtil.subBefore(methodName, ".",true);
        }

        /**
         * 获取method方法参数相关列表
         * @param invokeTarget 目标字符串
         * @return method方法相关参数列表
         */
        public static List<Object[]> getMethodParams(String invokeTarget) {
            String methodStr = StrUtil.subBetween(invokeTarget, "(", ")");
            if (StrUtil.isBlank(methodStr)) {
                return null;
            }
            String[] methodParams = methodStr.split(",");
            List<Object[]> classs = new LinkedList<>();
            for (int i = 0; i < methodParams.length; i++) {
                String str = StrUtil.trimToEmpty(methodParams[i]);
                // String字符串类型，包含'
                if (StrUtil.contains(str, "'")) {
                    classs.add(new Object[] { StrUtil.replace(str, "'", ""), String.class });
                }
                // boolean布尔类型，等于true或者false
                else if (StrUtil.equals(str, "true") || StrUtil.equalsIgnoreCase(str, "false")) {
                    classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
                }
                // long长整形，包含L
                else if (StrUtil.containsIgnoreCase(str, "L")) {
                    classs.add(new Object[] { Long.valueOf(StrUtil.replaceIgnoreCase(str, "L", "")), Long.class });
                }
                // double浮点类型，包含D
                else if (StrUtil.containsIgnoreCase(str, "D")) {
                    classs.add(new Object[] { Double.valueOf(StrUtil.replaceIgnoreCase(str, "D", "")), Double.class });
                }
                // 其他类型归类为整形
                else {
                    classs.add(new Object[] { Integer.valueOf(str), Integer.class });
                }
            }
            return classs;
        }

        /**
         * 获取参数类型
         * @param methodParams 参数相关列表
         * @return 参数类型列表
         */
        public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
            Class<?>[] classs = new Class<?>[methodParams.size()];
            int index = 0;
            for (Object[] os : methodParams) {
                classs[index] = (Class<?>) os[1];
                index++;
            }
            return classs;
        }

        /**
         * 获取参数值
         * @param methodParams 参数相关列表
         * @return 参数值列表
         */
        public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
            Object[] classs = new Object[methodParams.size()];
            int index = 0;
            for (Object[] os : methodParams) {
                classs[index] = (Object) os[0];
                index++;
            }
            return classs;
        }
}
